home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / Terminal 2.2 / Project / Sources / ZModem.c < prev    next >
Text File  |  1992-01-17  |  53KB  |  2,237 lines

  1. /*
  2.     Terminal 2.2
  3.     "ZModem.c"
  4. */
  5.  
  6. #ifdef THINK_C
  7. #include "MacHeaders"
  8. #endif
  9. #ifdef applec
  10. #pragma load ":(Objects):MacHeadersMPW"
  11. #pragma segment ZModem
  12. #endif
  13.  
  14. #include "Text.h"
  15. #include "Main.h"
  16. #include "Port.h"
  17. #include "CancelDialog.h"
  18. #include "Crc.h"
  19. #include "Utilities.h"
  20. #include "Strings.h"
  21. #include "FormatStr.h"
  22. #include "File.h"
  23. #include "MacBinary.h"
  24.  
  25. #include "ZModem.h"
  26.  
  27. /* #define MONITOR */                /* Debugging */
  28.  
  29. #ifdef MONITOR
  30. #include "Monitor.h"
  31. #endif
  32.  
  33. /* ----- Special characters -------------------------------------------- */
  34.  
  35. #define BS            0x08    /* Backspace */
  36. #define    LF            0x0A    /* Linefeed */
  37. #define CR            0x0D    /* Carriage return */
  38. #define DLE            0x10    /* Data link escape */
  39. #define XON            0x11    /* Flow control */
  40. #define XOFF        0x13    /* Flow control */
  41. #define CAN            0x18    /* Cancel */
  42. #define DEL            0x7F    /* Delete */
  43.  
  44. #define ZPAD        '*'        /* Padding character begins frames */
  45. #define ZDLE        0x18    /* Zmodem escape character ctrl-X */
  46. #define ZBIN        'A'        /* Binary header indicator (CRC-16) */
  47. #define ZHEX        'B'        /* HEX header indicator */
  48.  
  49. /* ----- Frame types --------------------------------------------------- */
  50.  
  51. #define ZRQINIT        0        /* Request receive init */
  52. #define ZRINIT        1        /* Receive init */
  53. #define ZSINIT        2        /* Send init sequence (optional) */
  54. #define ZACK        3        /* ACK to above */
  55. #define ZFILE        4        /* File name from sender */
  56. #define ZSKIP        5        /* To sender: skip this file */
  57. #define ZNAK        6        /* Last packet was garbled */
  58. #define ZABORT        7        /* Abort batch transfers */
  59. #define ZFIN        8        /* Finish session */
  60. #define ZRPOS        9        /* Resume data trans at this position */
  61. #define ZDATA        10        /* Data packet(s) follow */
  62. #define ZEOF        11        /* End of file */
  63. #define ZFERR        12        /* Fatal Read or Write error Detected */
  64. #define ZCRC        13        /* Request for file CRC and response */
  65. #define ZCHALLENGE    14        /* Receiver's Challenge */
  66. #define ZCOMPL        15        /* Request is complete */
  67. #define ZCAN        16        /* Other end canned session with 5 CANs */
  68. #define ZFREECNT    17        /* Request for free bytes on filesystem */
  69. #define ZCOMMAND    18        /* Command from sending program */
  70. #define ZSTDERR        19        /* Output to standard error, data follows */
  71.  
  72. /* ----- ZDLE sequences ------------------------------------------------ */
  73.  
  74. #define ZCRCE        'h'        /* CRC next, frame ends, header follows */
  75. #define ZCRCG        'i'        /* CRC next, frame continues nonstop */
  76. #define ZCRCQ        'j'        /* CRC next, frame continues, ZACK expected */
  77. #define ZCRCW        'k'        /* CRC next, ZACK expected, end of frame */
  78. #define ZRUB0        'l'        /* Translate to DEL 0x7F */
  79. #define ZRUB1        'm'        /* Translate to DEL 0xFF */
  80.  
  81. /* ----- Header structures --------------------------------------------- */
  82.  
  83. typedef struct {
  84.     unsigned long: 24;
  85.     unsigned long command: 8;    /* 0 or ZCOMMAND */
  86. } ZRQINITflags;
  87.  
  88. typedef struct {
  89.     unsigned long bufsize: 16;    /* Receiver's buffer size (bytes swapped) */
  90.     unsigned long: 7;
  91.     unsigned long canvhdr: 1;    /* Variable headers OK */
  92.     unsigned long esc8: 1;        /* Rx expects 8th bit to be escaped */
  93.     unsigned long escctl: 1;    /* Rx expects ctl chars to be escaped */
  94.     unsigned long canfc32: 1;    /* Rx can use 32 bit CRC */
  95.     unsigned long canlzw: 1;    /* Rx can uncompress */
  96.     unsigned long canrle: 1;    /* Rx can decode RLE */
  97.     unsigned long canbrk: 1;    /* Rx can send a break signal */
  98.     unsigned long canovio: 1;    /* Rx can receive data during disk I/O */
  99.     unsigned long canfdx: 1;    /* Rx can send and receive true FDX */
  100. } ZRINITflags;
  101.  
  102. typedef struct {
  103.     unsigned long: 24;
  104.     unsigned long esc8: 1;        /* Tx expects 8th bit to be escaped */
  105.     unsigned long escctl: 1;    /* Tx expects ctl chars to be escaped */
  106.     unsigned long: 6;
  107. } ZSINITflags;
  108.  
  109. typedef struct {
  110.     unsigned long: 1;
  111.     unsigned long sparse: 1;    /* Encoding for sparse file operations */
  112.     unsigned long: 5;
  113.     unsigned long canvhdr: 1;    /* Variable headers OK */
  114.     unsigned long transport: 8;    /* Transport options */
  115.     unsigned long skip: 1;        /* Skip file if not present at rx */
  116.     unsigned long: 2;
  117.     unsigned long manage: 5;    /* Management options */
  118.     unsigned long conv: 8;        /* Conversion options */
  119. } ZFILEflags;
  120.  
  121. typedef struct {
  122.     unsigned long: 31;
  123.     unsigned long ack: 1;        /* Acknowledge, then do command */
  124. } ZCOMMANDflags;
  125.  
  126. typedef union {
  127.     unsigned char b[4];
  128.     unsigned long position;        /* File position (low byte first) */
  129.     ZRQINITflags zrqinit;
  130.     ZRINITflags zrinit;
  131.     ZSINITflags zsinit;
  132.     ZFILEflags zfile;
  133.     ZCOMMANDflags zcommand;
  134. } HEADER;
  135.  
  136. /* ----- Conversion options, ZFILE frame ------------------------------- */
  137.  
  138. #define ZCBIN        1        /* Binary transfer - inhibit conversion */
  139. #define ZCNL        2        /* Convert NL to local eol convention */
  140. #define ZCRESUM        3        /* Resume interrupted file transfer */
  141.  
  142. /* ----- Management options, ZFILE frame ------------------------------- */
  143.  
  144. #define ZMNEWL        1        /* Transfer if source newer or longer */
  145. #define ZMCRC        2        /* Transfer if different file CRC or length */
  146. #define ZMAPND        3        /* Append contents to existing file (if any) */
  147. #define ZMCLOB        4        /* Replace existing file */
  148. #define ZMNEW        5        /* Transfer if source newer */
  149. #define ZMDIFF        6        /* Transfer if dates or lengths different */
  150. #define ZMPROT        7        /* Protect destination file */
  151.  
  152. /* ----- Transport options, ZFILE frame -------------------------------- */
  153.  
  154. #define ZTLZW        1        /* Lempel-Ziv compression */
  155. #define ZTRLE        3        /* Run Length encoding */
  156.  
  157. /* ----- Other constants ----------------------------------------------- */
  158.  
  159. #define ZATTNLEN    32        /* Max length of attention string */
  160. #define ZMAXSPLEN    1024    /* Max subpacket length */
  161.  
  162. /* ----- Return values (internal) -------------------------------------- */
  163.  
  164. #define GOTOR    0x0100
  165. #define GOTCRCE (GOTOR | ZCRCE)    /* ZDLE-ZCRCE received */
  166. #define GOTCRCG (GOTOR | ZCRCG)    /* ZDLE-ZCRCG received */
  167. #define GOTCRCQ (GOTOR | ZCRCQ)    /* ZDLE-ZCRCQ received */
  168. #define GOTCRCW (GOTOR | ZCRCW)    /* ZDLE-ZCRCW received */
  169.  
  170. /* ----- Globals ------------------------------------------------------- */
  171.  
  172. Byte ZAutoReceiveString[] = {
  173.     ZPAD, ZDLE, ZHEX,
  174.     '0', '0',                                    /* Type: ZRQINIT */
  175.     '0', '0', '0', '0', '0', '0', '0', '0',
  176.     '0', '0', '0', '0',                            /* CRC1 CRC2 */
  177.     CR,
  178.     0
  179. };
  180. Byte ZLastRx[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
  181.  
  182. #define GARBAGE 1400+2400        /* Garbage count before header */
  183. static jmp_buf CancelEnv;        /* Long jump if cancel or abort */
  184. static Boolean Zctlesc;            /* TRUE: escape all control characters */
  185. static Byte    *TxBuffer = 0;        /* Transmit buffer */
  186. static Byte    *TxPtr;                /* Pointer into transmit buffer */
  187.  
  188. /* Shared by transmit and receive */
  189. static short RefNum;            /* File reference number */
  190. static unsigned long Mark;        /* Current file position */
  191. static unsigned long Length;    /* Length of file */
  192. static unsigned long StartPos;    /* Start file position */
  193. static unsigned long StartTime;    /* Start time */
  194. static short Vers;                /* MacBinary version */
  195. static Byte *Buffer;            /* Block buffer + attention string + ... */
  196.  
  197. /* Transmit only */
  198. static unsigned long Txwindow;    /* Size of the transmitted window */
  199. static unsigned long Txwspac;    /* Spacing between ZCRCQ requests */
  200. static unsigned short Rxbuflen;    /* Receiver's max buffer length */
  201. static unsigned long Lastsync;    /* Last offset to which we got a ZRPOS */
  202. static unsigned long Lrxpos;    /* Receiver's last reported offset */
  203. static short BeenHereB4;        /* How many times ZRPOS same place */
  204.  
  205. /* Receive only */
  206. static Byte TryZhdrType;        /* Header type to send */
  207. static unsigned short Count;    /* Bytes in block buffer */
  208. #define Attn (Buffer+ZMAXSPLEN)    /* Sender's attention string */
  209. static unsigned short AttnLen;    /* Bytes in attention string */
  210. #define BinHdr (Attn+ZATTNLEN)    /* MacBinary header received */
  211. #define BUFFERSIZE (ZMAXSPLEN+ZATTNLEN+BinHeaderLength)
  212. static Boolean ConvertNL;        /* Convert newline to local eol */
  213.  
  214. /* ===== COMMON FUNCTIONS ============================================== */
  215.  
  216. #ifdef MONITOR
  217. /* ----- Translate ZModem constants ------------------------------------ */
  218.  
  219. static char *FrameTypes[] = {
  220.     "\pZRQINIT",
  221.     "\pZRINIT",
  222.     "\pZSINIT",
  223.     "\pZACK",
  224.     "\pZFILE",
  225.     "\pZSKIP",
  226.     "\pZNAK",
  227.     "\pZABORT",
  228.     "\pZFIN",
  229.     "\pZRPOS",
  230.     "\pZDATA",
  231.     "\pZEOF",
  232.     "\pZFERR",
  233.     "\pZCRC",
  234.     "\pZCHALLENGE",
  235.     "\pZCOMPL",
  236.     "\pZCAN",
  237.     "\pZFREECNT",
  238.     "\pZCOMMAND",
  239.     "\pZSTDERR"
  240. };
  241.  
  242. static char *ZFrameType (register short x)
  243. {
  244.     static char s[10];
  245.  
  246.     if (x < sizeof(FrameTypes)/sizeof(char *))
  247.         return FrameTypes[x];
  248.     NumToString(x, s);
  249.     return s;
  250. }
  251.  
  252. typedef struct {
  253.     Byte    c;
  254.     char    *s;
  255. } FRAMEND;
  256.  
  257. static FRAMEND ZFrameEnds[] = {
  258.     ZCRCE, "\pZCRCE",
  259.     ZCRCG, "\pZCRCG",
  260.     ZCRCQ, "\pZCRCQ",
  261.     ZCRCW, "\pZCRCW",
  262.     ZRUB0, "\pZRUB0",
  263.     ZRUB1, "\pZRUB1",
  264.     0, 0
  265. };
  266.  
  267. static char *ZFrameEnd (register Byte x)
  268. {
  269.     register FRAMEND *p = ZFrameEnds;
  270.     static char s[10];
  271.     
  272.     while (p->s) {
  273.         if (p->c == x)
  274.             return p->s;
  275.         ++p;
  276.     }
  277.     NumToString(x, s);
  278.     return s;
  279. }
  280. #endif
  281.  
  282. /* ----- Should we escape control characters? -------------------------- */
  283.  
  284. static Boolean Escape(void)
  285. {
  286.     return Settings.ZEscapeCtl || !Serial8Bits(Settings.portSetup);
  287. }
  288.  
  289. /* ----- Allocate memory for transmit buffer --------------------------- */
  290.  
  291. static short NewTxBuffer (register Boolean block)
  292. {
  293.     if (TxBuffer)
  294.         return 1;                /* Error: already allocated */
  295.     TxBuffer = (Byte *)NewPtr(block ?
  296.         2*(ZMAXSPLEN + 6) :        /* Worst case for transmitting block */
  297.         32);                    /* Worst case for transmitting header */
  298.     return TxBuffer ? 0 : memFullErr;
  299. }
  300.  
  301. /* ----- Dispose of transmit buffer ------------------------------------ */
  302.  
  303. static void DisposeTxBuffer (void)
  304. {
  305.     while (Busy)
  306.         ;
  307.     if (TxBuffer)
  308.         DisposPtr((Ptr)TxBuffer);
  309.     TxBuffer = 0;
  310. }
  311.  
  312. /* ----- Prepare new transmission -------------------------------------- */
  313.  
  314. static void InitTxBuffer (void)
  315. {
  316.     while (Busy)    /* Wait until previous transmission finished */
  317.         if (CheckCancel())
  318.             longjmp(CancelEnv, CANCEL);
  319.     TxPtr = TxBuffer;
  320. }
  321.  
  322. /* ----- Start transmission, don't wait -------------------------------- */
  323.  
  324. static void TransmitTxBuffer (void)
  325. {
  326.     SerialSend(TxBuffer, TxPtr - TxBuffer, &Busy);
  327. }
  328.  
  329. /* ----- Send more bytes ----------------------------------------------- */
  330.  
  331. static void SendString (register Byte *s, register unsigned short n)
  332. {
  333.     InitTxBuffer();
  334.     memcpy(TxPtr, s, n);
  335.     TxPtr += n;
  336.     TransmitTxBuffer();
  337. }
  338.  
  339. /* ----- Send cancel string -------------------------------------------- */
  340.  
  341. static void SendCancel(void)
  342. {
  343.     static Byte cs[] = {
  344.         CAN, CAN, CAN, CAN, CAN, CAN, CAN, CAN,
  345.         BS, BS, BS, BS, BS, BS, BS, BS, BS, BS
  346.     };
  347.  
  348.     SerialSend(cs, sizeof(cs), &Busy);
  349.     while (Busy)
  350.         ;
  351. }
  352.  
  353. /* ----- Sleep a while ------------------------------------------------- */
  354.  
  355. static void Sleep (register unsigned long ticks)
  356. {
  357.     register unsigned long start = Ticks;
  358.  
  359.     while((Ticks - start) < ticks)
  360.         if (CheckCancel())
  361.             longjmp(CancelEnv, CANCEL);
  362. }
  363.  
  364. /* ----- Send a byte --------------------------------------------------- */
  365.  
  366. static Byte SendByte (register Byte c)
  367. {
  368.     *TxPtr++ = c;
  369.     return c;
  370. }
  371.  
  372. /* ----- Send attention string ----------------------------------------- */
  373.  
  374. static void SendAttn (register Byte *s)
  375. {
  376.     while (Busy)
  377.         ;
  378.     while (*s) {
  379.         switch (*s) {
  380.             case 0xDD:        /* Send break signal */
  381.                 /* sendbrk(); */
  382.                 break;
  383.             case 0xDE:        /* Sleep 1 second */
  384.                 Sleep(60);
  385.                 break;
  386.             default:
  387.                 SerialSend(s, 1, &Busy);
  388.                 while (Busy)
  389.                     if (CheckCancel())
  390.                         longjmp(CancelEnv, CANCEL);
  391.         }
  392.         ++s;
  393.     }
  394. }
  395.  
  396. /* ----- Swap 4 bytes in long ------------------------------------------ */
  397.  
  398. static unsigned long Swap4 (register unsigned long n)
  399. {
  400.     register short i;
  401.     register unsigned long x = 0;
  402.  
  403.     for (i = 0; i < 4; ++i) {
  404.         x <<= 8;
  405.         x |= n & 0xFF;
  406.         n >>= 8;
  407.     }
  408.     return x;
  409. }
  410.  
  411. /* ----- Swap 2 bytes in short ----------------------------------------- */
  412.  
  413. static unsigned short Swap2 (register unsigned short n)
  414. {
  415.     register short i;
  416.     register unsigned short x = 0;
  417.  
  418.     for (i = 0; i < 2; ++i) {
  419.         x <<= 8;
  420.         x |= n & 0xFF;
  421.         n >>= 8;
  422.     }
  423.     return x;
  424. }
  425.  
  426. /* ----- Adjust header ------------------------------------------------- */
  427.  
  428. static void AdjustHeader (register Byte type, register HEADER *p)
  429. {
  430.     switch (type) {
  431.         case ZACK:
  432.         case ZRPOS:
  433.         case ZDATA:
  434.         case ZEOF:
  435.         case ZCRC:
  436.         case ZCHALLENGE:
  437.         case ZFREECNT:
  438.         case ZCOMPL:
  439.             p->position = Swap4(p->position);
  440.             break;
  441.         case ZRINIT:
  442.             p->zrinit.bufsize = Swap2(p->zrinit.bufsize);
  443.             break;
  444.     }
  445. }
  446.  
  447. /* ----- Send a byte as two hex digits --------------------------------- */
  448.  
  449. static Byte PutHex (register Byte c)
  450. {
  451.     static Byte digits[] = {
  452.         '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
  453.  
  454.     SendByte(digits[(c >> 4) & 0xF]);
  455.     SendByte(digits[c & 0xF]);
  456.     return c;
  457. }
  458.  
  459. /* ----- Send a byte with ZMODEM escape sequence encoding -------------- */
  460.  
  461. static Byte SendLine (register Byte c)
  462. {
  463.     register Byte b = c;
  464.     static Byte lastsent = 0;    /* Last byte sent */
  465.  
  466.     if (c & 0x60)        /* Non control character */
  467.         SendByte(lastsent = c);
  468.     else {
  469.         switch (c) {
  470.             case ZDLE:
  471.                 SendByte(ZDLE);
  472.                 SendByte(lastsent = c ^ 0x40);
  473.                 break;
  474.             case CR:    /* Escape CR followed by @ (Telenet net escape) */
  475.             case 0x80 | CR:
  476.                 if (!Zctlesc && (lastsent & 0x7F) != '@') {
  477.                     SendByte(lastsent = c);
  478.                     break;
  479.                 }
  480.                 /* Fall thru */
  481.             case DLE:
  482.             case 0x80 | DLE:
  483.             case XON:
  484.             case 0x80 | XON:
  485.             case XOFF:
  486.             case 0x80 | XOFF:
  487.                 SendByte(ZDLE);
  488.                 c ^= 0x40;
  489.                 SendByte(lastsent = c);
  490.                 break;
  491.             default:
  492.                 if (Zctlesc && !(c & 0x60)) {
  493.                     SendByte(ZDLE);
  494.                     c ^= 0x40;
  495.                 }
  496.                 SendByte(lastsent = c);
  497.         }
  498.     }
  499.     return b;
  500. }
  501.  
  502. /* ----- Send ZMODEM HEX header ---------------------------------------- */
  503.  
  504. static void SendHexHeader (register Byte type, HEADER hdr)
  505. {
  506.     register short i;
  507.     register unsigned short crc;
  508.  
  509.     AdjustHeader(type, &hdr);
  510.  
  511. #ifdef MONITOR
  512.     {
  513.         Byte mon[256];
  514.         FormatStr(mon, (Byte *)"\pTransmit HEX header %s",
  515.             ZFrameType(type));
  516.         MonitorText(mon);
  517.         MonitorDump(&hdr.b[0], 4);
  518.     }
  519. #endif
  520.  
  521.     InitTxBuffer();
  522.     SendByte(ZPAD);                                /* 1 */
  523.     SendByte(ZPAD);                                /* 1 */
  524.     SendByte(ZDLE);                                /* 1 */
  525.     SendByte(ZHEX);                                /* 1 */
  526.     crc = UpdateCRC(PutHex(type), 0);
  527.     for (i = 0; i < 4; ++i)
  528.         crc = UpdateCRC(PutHex(hdr.b[i]), crc);    /* 8 */
  529.     PutHex((crc >> 8) & 0xFF);                    /* 2 */
  530.     PutHex(crc & 0xFF);                            /* 2 */
  531.     SendByte(CR);                                /* 1 */
  532.     SendByte(LF);                                /* 1 */
  533.     if (type != ZFIN && type != ZACK)
  534.         SendByte(XON);                            /* 1 */
  535.     /*SerialFlush();*/
  536.     TransmitTxBuffer();                /* Worst case:    19 bytes */
  537. }
  538.  
  539. /* ----- Send ZMODEM binary header ------------------------------------- */
  540.  
  541. static void SendBinaryHeader (register Byte type, HEADER hdr)
  542. {
  543.     register short i;
  544.     register unsigned short crc;
  545.  
  546.     AdjustHeader(type, &hdr);
  547.  
  548. #ifdef MONITOR
  549.     {
  550.         Byte mon[256];
  551.         FormatStr(mon, (Byte *)"\pTransmit BIN header %s",
  552.             ZFrameType(type));
  553.         MonitorText(mon);
  554.         MonitorDump(&hdr.b[0], 4);
  555.     }
  556. #endif
  557.  
  558.     InitTxBuffer();
  559.     SendByte(ZPAD);                                /* 1 */
  560.     SendByte(ZDLE);                                /* 1 */
  561.     SendByte(ZBIN);                                /* 1 */
  562.     crc = UpdateCRC(SendLine(type), 0);
  563.     for (i = 0; i < 4; ++i)
  564.         crc = UpdateCRC(SendLine(hdr.b[i]), crc);    /* 8 */
  565.     SendLine((crc >> 8) & 0xFF);                    /* 2 */
  566.     SendLine(crc & 0xFF);                            /* 2 */
  567.     if (type != ZDATA)
  568.         SerialFlush();                                            /*****/
  569.     TransmitTxBuffer();                /* Worst case:    15 bytes */
  570. }
  571.  
  572. /* ----- Send binary array with ending ZDLE sequence ------------------- */
  573.  
  574. static void SendData (
  575.     register Byte *buf,
  576.     unsigned short length,
  577.     Byte frameend)
  578. {
  579.     register unsigned short crc;
  580.  
  581. #ifdef MONITOR
  582.     {
  583.         Byte mon[256];
  584.         FormatStr(mon, (Byte *)"\pTransmit %i bytes %s",
  585.             length, ZFrameEnd(frameend));
  586.         MonitorText(mon);
  587.         MonitorDump(buf, length);
  588.     }
  589. #endif
  590.  
  591.     InitTxBuffer();
  592.     for (crc = 0 ; length; ++buf, --length) {
  593.         SendLine(*buf);
  594.         crc = UpdateCRC(*buf, crc);
  595.     }
  596.     SendByte(ZDLE);
  597.     SendByte(frameend);
  598.     crc = UpdateCRC(frameend, crc);
  599.     SendLine((crc >> 8) & 0xFF);
  600.     SendLine(crc & 0xFF);
  601.     if (frameend == ZCRCW) {
  602.         SendByte(XON);
  603.         SerialFlush();
  604.     }
  605.     TransmitTxBuffer();
  606. }
  607.  
  608. /* ----- Read character with timeout ----------------------------------- */
  609.  
  610. static short ReadByte (
  611.     register Byte *c,                /* Character (result) */
  612.     register unsigned long timeout)    /* Timeout in ticks */
  613. {
  614.     register unsigned long start;
  615.     register long count;
  616.     static short abort = 0;    /* CAN counter */
  617.  
  618.     /* If a character is available don't check for cancel,
  619.     this speeds up reception */
  620.  
  621.     if (!SerialRead(c, 1)) {
  622.         start = Ticks;
  623.         do {
  624.             if ((Ticks - start) > timeout)
  625.                 return TIMEOUT;
  626.             if (!(count = SerialRead(c, 1)) && CheckCancel())
  627.                 longjmp(CancelEnv, CANCEL);
  628.         } while (count == 0);
  629.     }
  630.     if (*c == CAN) {
  631.         if (++abort >= 5)
  632.             longjmp(CancelEnv, ABORT);
  633.     } else
  634.         abort = 0;
  635.     return FINE;
  636. }
  637.  
  638. /* ----- Wait for ZPAD character --------------------------------------- */
  639.  
  640. static short WaitZPAD (
  641.     unsigned long timeout,        /* Timeout in ticks */
  642.     register unsigned short n)    /* Max bytes before start of frame */
  643. {
  644.     Byte c;
  645.  
  646.     for (;;)
  647.         switch (ReadByte(&c, timeout)) {
  648.             case FINE:
  649.                 if ((c & 0x7F) == ZPAD)
  650.                     return FINE;
  651.                 if (--n == 0)
  652.                     return ERROR;
  653.                 break;
  654.             case TIMEOUT:
  655.                 return TIMEOUT;
  656.         }
  657. }
  658.  
  659. /* ----- Read character with timemout, eat parity, XON and XOFF -------- */
  660.  
  661. static short ReadByte2 (
  662.     register Byte *c,                /* Character (result) */
  663.     register unsigned long timeout)    /* Timeout in ticks */
  664. {
  665.     for (;;) {
  666.         if (ReadByte(c, timeout))
  667.             return TIMEOUT;
  668.         switch (*c &= 0x7F) {
  669.             case XON:
  670.             case XOFF:
  671.                 break;
  672.             default:
  673.                 if (Zctlesc && !(*c & 0x60))
  674.                     break;
  675.             case CR:
  676.             case LF:
  677.             case ZDLE:
  678.                 return FINE;
  679.         }
  680.     }
  681. }
  682.  
  683. /* ----- Decode two lower case hex digits into an 8 bit byte value ----- */
  684.  
  685. static short GetHex (register Byte *c)
  686. {
  687.     register short i;
  688.     Byte n;
  689.  
  690.     *c = 0;
  691.     for (i = 0; i < 2; ++i) {
  692.         *c <<= 4;
  693.         if (ReadByte2(&n, Settings.ZTimeout))
  694.             return TIMEOUT;
  695.         if (n >= '0' && n <= '9')
  696.             n -= '0';
  697.         else
  698.             if (n >= 'a' && n <= 'f')
  699.                 n -= 'a' - 10;
  700.             else
  701.                 return ERROR;
  702.         *c += n;
  703.     }
  704.     return FINE;
  705. }
  706.  
  707. /* ----- Read a byte, checking for ZMODEM escape encoding -------------- */
  708.  
  709. static short ZdleRead (register Byte *c)
  710. {
  711.     do {
  712.         if (ReadByte(c, Settings.ZTimeout))
  713.             return TIMEOUT;
  714.         if (*c & 0x60)                        /* Non-control character */
  715.             return FINE;
  716.         switch (*c) {                        /* Control character */
  717.             case ZDLE:
  718.             case XON:
  719.             case 0x80 | XON:
  720.             case XOFF:
  721.             case 0x80 | XOFF:
  722.                 break;                        /* Ignore XON/XOFF */
  723.             default:
  724.                 if (!Zctlesc)
  725.                     return FINE;
  726.                 break;                        /* Ignore ctrl if escaping */
  727.         }
  728.     } while (*c != ZDLE);
  729.  
  730.     /* Previous character was ZDLE */
  731.  
  732.     for (;;) {
  733.         if (ReadByte(c, Settings.ZTimeout))
  734.             return TIMEOUT;
  735.         switch (*c) {
  736.             case ZCRCE:
  737.             case ZCRCG:
  738.             case ZCRCQ:
  739.             case ZCRCW:
  740.                 return *c | GOTOR;            /* Frame end */
  741.             case ZRUB0:
  742.                 *c = DEL;
  743.                 return FINE;
  744.             case ZRUB1:
  745.                 *c = 0x80 | DEL;
  746.                 return FINE;
  747.             case XON:
  748.             case 0x80 | XON:
  749.             case XOFF:
  750.             case 0x80 | XOFF:
  751.                 break;                        /* Ignore XON/XOFF */
  752.             default:
  753.                 if (Zctlesc && !(*c & 0x60))
  754.                     break;                    /* Ignore ctrl if escaping */
  755.                 if ((*c & 0x60) != 0x40)    /* Must be -10- ---- */
  756.                     return ERROR;
  757.                 *c ^= 0x40;                    /* Invert bit 6 */
  758.                 return FINE;
  759.         }
  760.     }
  761. }
  762.  
  763. /* ----- Receive a binary style header (type and position) ------------- */
  764.  
  765. static short ReceiveBinaryHeader (
  766.     register Byte *type,
  767.     register Byte *hdr)
  768. {
  769.     register short n, err;
  770.     register unsigned short crc;
  771.     Byte c;
  772.  
  773.     /* Header type */
  774.  
  775.     if (err = ZdleRead(type))
  776.         return err;        /* TIMEOUT, ERROR, GOTxxxx */
  777.     crc = UpdateCRC(*type, 0);
  778.  
  779.     /* Header info (4 bytes) */
  780.  
  781.     for (n = 0; n < 4; ++n, ++hdr) {
  782.         if (err = ZdleRead(hdr))
  783.             return err;    /* TIMEOUT, ERROR, GOTxxxx */
  784.         crc = UpdateCRC(*hdr, crc);
  785.     }
  786.  
  787.     /* CRC (2 bytes) */
  788.  
  789.     if (err = ZdleRead(&c))
  790.         return err;        /* TIMEOUT, ERROR, GOTxxxx */
  791.     crc = UpdateCRC(c, crc);
  792.     if (err = ZdleRead(&c))
  793.         return err;        /* TIMEOUT, ERROR, GOTxxxx */
  794.     if (crc = UpdateCRC(c, crc))
  795.         return ERROR;    /* Bad CRC */
  796.  
  797.     return FINE;
  798. }
  799.  
  800. /* ----- Receive a hex style header (type and position) ---------------- */
  801.  
  802. static short ReceiveHexHeader (
  803.     register Byte *type,
  804.     register Byte *hdr)
  805. {
  806.     register short n, err;
  807.     register unsigned short crc;
  808.     Byte c;
  809.  
  810.     /* Header type */
  811.  
  812.     if (err = GetHex(type))
  813.         return err;
  814.     crc = UpdateCRC(*type, 0);
  815.  
  816.     /* Header info (4 bytes) */
  817.  
  818.     for (n = 0; n < 4; ++n, ++hdr) {
  819.         if (err = GetHex(hdr))
  820.             return err;
  821.         crc = UpdateCRC(*hdr, crc);
  822.     }
  823.  
  824.     /* CRC (2 bytes) */
  825.  
  826.     if (err = GetHex(&c))
  827.         return err;
  828.     crc = UpdateCRC(c, crc);
  829.     if (err = GetHex(&c))
  830.         return err;
  831.     if (crc = UpdateCRC(c, crc))
  832.         return ERROR;    /* Bad CRC */
  833.  
  834.     /* Throw away possible CR/LF */
  835.  
  836.     if (ReadByte(&c, 1) == FINE && (c & 0x7F) == CR)
  837.         ReadByte(&c, 1);
  838.  
  839.     return FINE;
  840. }
  841.  
  842. /* ----- Read a ZMODEM header (either binary or hex) ------------------- */
  843.  
  844. static short GetHeader (
  845.     register Byte *type,
  846.     register HEADER *hdr)
  847. {
  848.     register short err;
  849.     register short n = GARBAGE;
  850.     Byte c;
  851. #ifdef MONITOR
  852.     short headerNature = 0;
  853. #endif
  854.  
  855.     /* Wait for ZPAD character */
  856.  
  857.     if (err = WaitZPAD(Settings.ZTimeout, GARBAGE))
  858.         goto done;
  859.  
  860.     /* Just got ZPAD character, wait for ZDLE character */
  861.  
  862.     do {
  863.         if (err = ReadByte2(&c, Settings.ZTimeout))
  864.             goto done;
  865.         switch (c) {
  866.             case ZDLE:        /* This is what we want */
  867.             case ZPAD:        /* May be more than one ZPAD */
  868.             case ZPAD | 0x80:
  869.                 break;
  870. again:
  871.             default:        /* Garbage */
  872.                 if (--n == 0) {
  873.                     err = ERROR;
  874.                     goto done;
  875.                 }
  876.                 break;
  877.         }
  878.     } while (c != ZDLE);
  879.  
  880.     /* Just got ZPAD-ZDLE sequence */
  881.  
  882.     if (err = ReadByte2(&c, Settings.ZTimeout))
  883.         goto done;
  884.     switch (c) {
  885.         case ZBIN:        /* It's a binary header */
  886. #ifdef MONITOR
  887.             headerNature = 1;
  888. #endif
  889.             err = ReceiveBinaryHeader(type, hdr->b);
  890.             break;
  891.         case ZHEX:        /* It's a hex header */
  892. #ifdef MONITOR
  893.             headerNature = 2;
  894. #endif
  895.             err = ReceiveHexHeader(type, hdr->b);
  896.             break;
  897.         default:        /* Garbage */
  898.             goto again;
  899.     }
  900.     AdjustHeader(*type, hdr);
  901.  
  902.     /* ZPAD ZDLE ZBIN/ZHEX ... */
  903.  
  904. done:
  905.  
  906. #ifdef MONITOR
  907.     {
  908.         static char *binhex[] = { "\pBIN", "\pHEX" };
  909.         Byte mon[256];
  910.         if (headerNature) {
  911.             FormatStr(mon, (Byte *)"\pReceived %s header %s error %i",
  912.                 binhex[headerNature - 1],
  913.                 ZFrameType(*type),
  914.                 err);
  915.             MonitorText(mon);
  916.             MonitorDump(hdr->b, 4);
  917.         } else {
  918.             FormatStr(mon, (Byte *)"\pReceived error %i", err);
  919.             MonitorText(mon);
  920.         }
  921.     }
  922. #endif
  923.  
  924.     return err;
  925. }
  926.  
  927. /* ----- Receive array with ending ZDLE sequence and CRC --------------- */
  928.  
  929. static short ReceiveData (
  930.     register Byte *buf,        /* Buffer for data */
  931.     unsigned short length,    /* Max size of buffer */
  932.     unsigned short *count,    /* Number of data bytes received */
  933.     Byte *framend)            /* Frame end character received */
  934. {
  935.     register unsigned short crc = 0;
  936.     register Byte *max = buf + length;
  937.     register short err;
  938.     Byte c;
  939.  
  940.     *framend = 0xFF;
  941.     while (buf <= max) {
  942.         switch (err = ZdleRead(&c)) {
  943.             case FINE:                /* Data byte */
  944.                 crc = UpdateCRC(c, crc);
  945.                 *buf++ = (ConvertNL && c == LF) ? CR : c;
  946.                 break;
  947.             case GOTCRCE:            /* Frame end, CRC follows */
  948.             case GOTCRCG:
  949.             case GOTCRCQ:
  950.             case GOTCRCW:
  951.                 *count = length - (max - buf);
  952.                 crc = UpdateCRC(*framend = c, crc);
  953.                 if (err = ZdleRead(&c))
  954.                     goto done;
  955.                 crc = UpdateCRC(c, crc);
  956.                 if (err = ZdleRead(&c))
  957.                     goto done;
  958.                 if (crc = UpdateCRC(c, crc))
  959.                     err = ERROR;    /* Bad CRC */
  960.                 else
  961.                     err = FINE;
  962.                 goto done;
  963.             default:                /* TIMEOUT, ERROR, ... */
  964.                 *count = length - (max - buf);
  965.                 goto done;
  966.         }
  967.     }
  968.     *count = length - (max - buf);
  969.     err = ERROR;                    /* Data subpacket too long */
  970.  
  971. done:
  972. #ifdef MONITOR
  973.     {
  974.         Byte mon[256];
  975.         FormatStr(mon, (Byte *)"\pReceived %i bytes, end %s (error: %i)",
  976.             *count, ZFrameEnd(*framend), err);
  977.         MonitorText(mon);
  978.         MonitorDump(buf - *count, *count);
  979.     }
  980. #endif
  981.     return err;
  982. }
  983.  
  984. /* ----- Update progress indicator ------------------------------------- */
  985.  
  986. static void Update (register Byte *text, register long error)
  987. {
  988.     register unsigned long n = Mark - StartPos;
  989.     register unsigned long m = (Length > StartPos) ? Length - StartPos : 0;
  990.  
  991.     UpdateProgress(
  992.         Mark,
  993.         Length,
  994.         (m && n) ? ((Time - StartTime)*(m - n))/n : 0,
  995.         Count,
  996.         error,
  997.         text);
  998. }
  999.  
  1000. /* ----- Make info string for progress dialog -------------------------- */
  1001.  
  1002. static void MakeInfo(void)
  1003. {
  1004.     register Byte s[256];
  1005.     Byte *c;
  1006.     Byte *v;
  1007.  
  1008.     c = Zctlesc ? (Byte *)"\pEscape-Ctrl" : EmptyStr;
  1009.     switch (Vers) {
  1010.         case 0:
  1011.             v = MyString(STR_P, P_TEXT);
  1012.             break;
  1013.         case 1:
  1014.             v = MyString(STR_P, P_BINARY1);
  1015.             break;
  1016.         case 2:
  1017.             v = MyString(STR_P, P_BINARY2);
  1018.             break;
  1019.         default:
  1020.             v = EmptyStr;
  1021.     }
  1022.     FormatStr(s, (Byte *)"\pZModem %s rx=%i %s", c, Rxbuflen, v);
  1023.     InfoProgress(s);
  1024. }
  1025.  
  1026. /* ----- Convert between Macintosh time and ZModem time ---------------- */
  1027.  
  1028. static DateTimeRec ZTimeOrigin = { 1970, 1, 1, 0, 0, 0, 0 };
  1029.  
  1030. static void ConvertTime (Boolean toMac, unsigned long *t)
  1031. {
  1032.     unsigned long t0;
  1033.  
  1034.     Date2Secs(&ZTimeOrigin, &t0);
  1035.     *t = toMac ? (*t + t0) : (*t - t0);
  1036. }
  1037.  
  1038. /* ===== TRANSMIT ====================================================== */
  1039.  
  1040. /* ----- Fill buffer --------------------------------------------------- */
  1041.  
  1042. static short ReadBuffer (
  1043.     register long *count,
  1044.     register Byte *buf)
  1045. {
  1046.     register long x = *count;
  1047.  
  1048.     return FSRead(RefNum, count, buf) || *count != x;
  1049. }
  1050.  
  1051. /* ----- Set file position --------------------------------------------- */
  1052.  
  1053. static short Seek (register unsigned long position)
  1054. {
  1055.     return SetFPos(RefNum, fsFromStart, position);
  1056. }
  1057.  
  1058. /* ----- Respond to receiver's complaint, get back in sync ------------- */
  1059.  
  1060. static short GetInSync (
  1061.     Boolean flag,    /* TRUE: ZACK always returns */
  1062.     Byte *type)
  1063. {
  1064.     register short retry;
  1065.     register short err;
  1066.     HEADER hdr;
  1067.  
  1068.     for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1069.         Update((Byte *)"\psync", retry);
  1070.         switch (GetHeader(type, &hdr)) {
  1071.             case FINE:
  1072.                 switch (*type) {
  1073.                     case ZRPOS:
  1074.                         if (Seek(hdr.position)) {
  1075.                             err = ERROR;
  1076.                             goto done;
  1077.                         }
  1078.                         Lrxpos = Mark = hdr.position;
  1079.                         if (Lastsync == hdr.position &&
  1080.                                 ++BeenHereB4 > 4 && Count > 32)
  1081.                                     Count /= 2;
  1082.                         Lastsync = hdr.position;
  1083.                         err = FINE;
  1084.                         goto done;
  1085.                     case ZACK:
  1086.                         Lrxpos = hdr.position;
  1087.                         if (flag || Mark == hdr.position) {
  1088.                             err = FINE;
  1089.                             goto done;
  1090.                         }
  1091.                         break;    /* Ignore this ZACK */
  1092.                     case ZCAN:
  1093.                     case ZABORT:
  1094.                     case ZFIN:
  1095.                         goto error;
  1096.                     case ZRINIT:
  1097.                     case ZSKIP:
  1098.                         err = FINE;
  1099.                         goto done;
  1100.                 }
  1101.                 break;
  1102.             case TIMEOUT:
  1103.                 goto error;
  1104.         }
  1105.         hdr.position = 0;
  1106.         SendHexHeader(ZNAK, hdr);
  1107.     }
  1108. error:
  1109.     err = ERROR;
  1110. done:
  1111.     Update(EmptyStr, 0);
  1112.     return err;
  1113. }
  1114.  
  1115. /* ----- Send the data in the file ------------------------------------- */
  1116.  
  1117. static short SendFileData (void)
  1118. {
  1119.     short junkcount;        /* Counts garbage chars received */
  1120.     unsigned long txwcnt;    /* Counter used to space ACK requests */
  1121.     short eofseen;            /* End of file seen (file read error) */
  1122.     Byte type;                /* Header type */
  1123.     HEADER hdr;                /* Header */
  1124.     short err;                /* Error code */
  1125.     short newcnt;            /* Controls receiver's buffer */
  1126.     long n;                    /* Transmit buffer length */
  1127.     Byte e;                    /* Frame end character */
  1128.  
  1129.  
  1130.     Lastsync = (StartPos = Lrxpos = Mark) - 1;
  1131.     junkcount = 0;
  1132.     BeenHereB4 = 0;
  1133.  
  1134. somemore:
  1135.     if (FALSE) {
  1136.  
  1137. waitack:
  1138.         junkcount = 0;
  1139.         err = GetInSync(FALSE, &type);
  1140. gotack:
  1141.         if (err)
  1142.             return ERROR;
  1143.         switch (type) {
  1144.             case ZSKIP:
  1145.             case ZRINIT:
  1146.                 return FINE;
  1147.             case ZACK:
  1148.             case ZRPOS:
  1149.                 break;
  1150.             default:
  1151.                 return ERROR;
  1152.         }
  1153.  
  1154.         /* Check reverse channel (but don't wait) */
  1155.  
  1156.         if (CheckCancel())
  1157.             longjmp(CancelEnv, CANCEL);
  1158.         while (SerialCheck()) {
  1159.             Byte c;
  1160.             SerialFastRead(&c, 1);
  1161.             switch (c) {
  1162.                 case CAN:
  1163.                 case ZPAD:
  1164.                     err = GetInSync(TRUE, &type);
  1165.                     goto gotack;
  1166.                 case XOFF:        /* Wait a while for an XON */
  1167.                 case XOFF | 0x80:
  1168.                     ReadByte(&c, 100);
  1169.             }
  1170.         }
  1171.  
  1172.     }    /* somemore */
  1173.  
  1174.     /* Send ZDATA header */
  1175.  
  1176.     hdr.position = Mark;
  1177.     SendBinaryHeader(ZDATA, hdr);
  1178.  
  1179.     /* Send one or more data subpackets */
  1180.  
  1181.     newcnt = Rxbuflen;
  1182.     txwcnt = 0;
  1183.     do {
  1184.  
  1185.         /* Send data subpacket */
  1186.  
  1187.         n = Count;
  1188.         if (eofseen = ReadBuffer(&n, Buffer))
  1189.             e = ZCRCE;
  1190.         else if (junkcount > 3)
  1191.             e = ZCRCW;
  1192.         else if (Mark == Lastsync)
  1193.             e = ZCRCW;
  1194.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1195.             e = ZCRCW;
  1196.         else if (Txwindow && (txwcnt += n) >= Txwspac) {
  1197.             txwcnt = 0;
  1198.             e = ZCRCQ;
  1199.         } else
  1200.             e = ZCRCG;
  1201.         SendData(Buffer, n, e);
  1202.         Mark += n;
  1203.         Update(EmptyStr, 0);
  1204.  
  1205.         /* Wait for ZACK if necessary */
  1206.  
  1207.         if (e == ZCRCW)
  1208.             goto waitack;
  1209.  
  1210.         /* Check reverse channel (but don't wait) */
  1211.  
  1212.         if (CheckCancel())
  1213.             longjmp(CancelEnv, CANCEL);
  1214.         while (SerialCheck()) {
  1215.             Byte c;
  1216.             SerialFastRead(&c, 1);
  1217.             switch (c) {
  1218.                 case CAN:
  1219.                 case ZPAD:
  1220.                     err = GetInSync(TRUE, &type);
  1221.                     if (!err && type == ZACK)
  1222.                         break;
  1223.                     /* zcrce - dinna wanna starta ping-pong game */
  1224.                     SendData(Buffer, 0, ZCRCE);
  1225.                     goto gotack;
  1226.                 case XOFF:        /* Wait a while for an XON */
  1227.                 case XOFF | 0x80:
  1228.                     ReadByte(&c, 100);
  1229.                 default:
  1230.                     ++junkcount;
  1231.                     break;
  1232.             }
  1233.         }
  1234.  
  1235.         /* Make sure to stay in transmit window */
  1236.  
  1237.         if (Txwindow) {
  1238.             while ((Mark - Lrxpos) >= Txwindow) {
  1239.                 if (e != ZCRCQ)
  1240.                     SendData(Buffer, 0, e = ZCRCQ);
  1241.                 err = GetInSync(TRUE, &type);
  1242.                 if (err || type != ZACK) {
  1243.                     SendData(Buffer, 0, ZCRCE);
  1244.                     goto gotack;
  1245.                 }
  1246.             }
  1247.         }
  1248.     } while (!eofseen);
  1249.  
  1250.     /* Send ZEOF header, wait for ZRINIT header from receiver */
  1251.  
  1252.     for (;;) {
  1253.         hdr.position = Mark;
  1254.         SendBinaryHeader(ZEOF, hdr);
  1255.         if (GetInSync(FALSE, &type))
  1256.             return ERROR;
  1257.         switch (type) {
  1258.             case ZRINIT:
  1259.             case ZSKIP:
  1260.                 return FINE;
  1261.             case ZACK:
  1262.                 break;
  1263.             case ZRPOS:
  1264.                 goto somemore;
  1265.             default:
  1266.                 return ERROR;
  1267.         }
  1268.     }
  1269. }
  1270.  
  1271. /* ----- Invite receiver ----------------------------------------------- */
  1272.  
  1273. static short Invitation (void)
  1274. {
  1275.     HEADER hdr;
  1276.     register short retry;
  1277.     register short err;
  1278.  
  1279.     for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1280.         Update(EmptyStr, retry);
  1281.         hdr.position = 0;
  1282.         SendHexHeader(ZRQINIT, hdr);
  1283.         if ((err = WaitZPAD(Settings.ZTimeout, 1000)) == FINE) {
  1284.             Update(EmptyStr, 0);
  1285.             return FINE;
  1286.         }
  1287.     }
  1288.     return TIMEOUT;
  1289. }
  1290.  
  1291. /* ----- Send invitation to receiver, get receiver's parameters -------- */
  1292.  
  1293. static short SessionStartup (void)
  1294. {
  1295.     register short retry;
  1296.     register short err;
  1297.     register Byte *message = EmptyStr;
  1298.     Byte type;
  1299.     HEADER hdr;
  1300.  
  1301.     StartTime = Time;
  1302.     for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1303.         Update(message, retry);
  1304.         switch (GetHeader(&type, &hdr)) {
  1305.             case FINE:
  1306.                 switch (type) {
  1307.                     case ZRINIT:        /* This is what we want */
  1308.                         message = (Byte *)"\pZRINIT";
  1309.  
  1310.                         /* Set transfer parameters */
  1311.  
  1312.                         Rxbuflen = hdr.zrinit.bufsize;
  1313.                         Txwindow = Settings.ZWindow;
  1314.                         Txwspac = Settings.Zcrcq;
  1315.                         Count = Settings.ZPacket;
  1316. #ifdef XXX
  1317.                         if (Txwindow < 256)
  1318.                             Txwindow = 256;
  1319.                         Txwindow = (Txwindow/64) * 64;
  1320.                         Txwspac = Txwindow/4;
  1321.                         if (Count > Txwspac ||
  1322.                                 (!Count && Txwspac < ZMAXSPLEN))
  1323.                             Count = Txwspac;
  1324. #endif
  1325.                         if (!hdr.zrinit.canfdx)
  1326.                             Txwindow = 0;
  1327.                         if (Rxbuflen && Count > Rxbuflen)
  1328.                             Count = Rxbuflen;
  1329. #ifdef MONITOR
  1330.     {
  1331.         Byte mon[256];
  1332.         if (hdr.zrinit.canvhdr)
  1333.             MonitorText((Byte *)"\pCANVHDR");
  1334.         if (hdr.zrinit.esc8)
  1335.             MonitorText((Byte *)"\pESC8");
  1336.         if (hdr.zrinit.escctl)
  1337.             MonitorText((Byte *)"\pESCCTL");
  1338.         if (hdr.zrinit.canfc32)
  1339.             MonitorText((Byte *)"\pCRC32");
  1340.         if (hdr.zrinit.canlzw)
  1341.             MonitorText((Byte *)"\pLZW");
  1342.         if (hdr.zrinit.canrle)
  1343.             MonitorText((Byte *)"\pRLE");
  1344.         if (hdr.zrinit.canbrk)
  1345.             MonitorText((Byte *)"\pBRK");
  1346.         if (hdr.zrinit.canovio)
  1347.             MonitorText((Byte *)"\pOVIO");
  1348.         if (hdr.zrinit.canfdx)
  1349.             MonitorText((Byte *)"\pFDX");
  1350.         FormatStr(mon,
  1351.             (Byte *)"\pRxbuflen=%i Count=%i Txwindow=%l Txwspac=%l",
  1352.             Rxbuflen, Count, Txwindow, Txwspac);
  1353.         MonitorText(mon);
  1354.     }
  1355. #endif
  1356.  
  1357.                         /* No need to send an ZSINIT frame if ... */
  1358.  
  1359.                         Zctlesc = hdr.zrinit.escctl || Escape(); 
  1360.                         if (!Escape() || hdr.zrinit.escctl) {
  1361.                             err = FINE;
  1362.                             goto done;
  1363.                         }
  1364.                         for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1365.                             /* ZSINIT header */
  1366.                             hdr.position = 0;
  1367.                             hdr.zsinit.escctl = 1;
  1368.                             SendBinaryHeader(ZSINIT, hdr);
  1369.                             Update(message, retry);
  1370.                             /* Our attention string (empty string) */
  1371.                             type = 0;
  1372.                             SendData(&type, 1, ZCRCW);
  1373.                             /* Wait for ZACK header from receiver */
  1374.                             if (!GetHeader(&type, &hdr) && type == ZACK) {
  1375.                                 err = FINE;
  1376.                                 goto done;
  1377.                             }
  1378.                         }
  1379.                         err = TIMEOUT;
  1380.                         goto done;
  1381.  
  1382.                     case ZCHALLENGE:    /* Echo challenge number */
  1383.                         SendHexHeader(ZACK, hdr);
  1384.                         message = (Byte *)"\pZCHALLENGE";
  1385.                         break;
  1386.                     case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1387.                         hdr.position = 0;
  1388.                         SendHexHeader(ZRQINIT, hdr);
  1389.                         message = (Byte *)"\pZRQINIT";
  1390.                         break;
  1391.                     case ZRQINIT:
  1392.                         if (!hdr.zrqinit.command)
  1393.                             break;    /* Ignore (our echo) */
  1394.                         /* Fall thru */
  1395.                     default:
  1396.                         hdr.position = 0;
  1397.                         SendHexHeader(ZNAK, hdr);
  1398.                         message = (Byte *)"\p->ZNAK";
  1399.                         break;
  1400.                 }
  1401.             case TIMEOUT:
  1402.                 err = TIMEOUT;
  1403.                 goto done;
  1404.             default:
  1405.                 hdr.position = 0;
  1406.                 SendHexHeader(ZNAK, hdr);
  1407.                 message = (Byte *)"\p->ZNAK";
  1408.                 break;
  1409.             }
  1410.     }
  1411.     err = TIMEOUT;    /* Retry count exhausted */
  1412. done:
  1413.     Update(EmptyStr, 0);
  1414.     return err;
  1415. }
  1416.  
  1417. /* ----- Send file information ----------------------------------------- */
  1418.  
  1419. static short SendFileInfo (
  1420.     Byte *name,                    /* File name */
  1421.     unsigned long size,            /* File size */
  1422.     Boolean text,                /* Text file? */
  1423.     unsigned long modif,        /* Modification date */
  1424.     unsigned long *startpos)    /* Start position */
  1425. {
  1426.     register Byte *p;
  1427.     register Byte s[30];
  1428.     register short retry;
  1429.     register short err;
  1430.     Byte *message;
  1431.     Byte buffer[128];
  1432.     Byte type;
  1433.     HEADER hdr;
  1434.  
  1435.     /* File name as zero terminated ASCII string */
  1436.  
  1437.     p = buffer;
  1438.     memcpy(p, name + 1, *name);
  1439.     p += *name;
  1440.     *p++ = 0;
  1441.  
  1442.     /* File size as decimal ASCII digits */
  1443.  
  1444.     NumToString(size, s);
  1445.     memcpy(p, s + 1, *s);
  1446.     p += *s;
  1447.     *p++ = ' ';
  1448.  
  1449.     /* Modification date: octal string = seconds since 1/1/1970 UTC */
  1450.     ConvertTime(FALSE, &modif);    /* -> ZModem time */
  1451.  
  1452.     {
  1453.         register Byte *t = s + sizeof(s);
  1454.         register unsigned long n = modif;
  1455.  
  1456.         do {
  1457.             *(--t) = n % 8 + '0';
  1458.             n /= 8;
  1459.         } while (n);
  1460.         memcpy(p, t, n = sizeof(s) - (t - s));
  1461.         p += n;
  1462.     }
  1463.     *p++ = ' ';
  1464.  
  1465.     /* File mode (octal string) */
  1466.  
  1467.     *p++ = '0';
  1468.     *p++ = ' ';
  1469.  
  1470.     /* Serial number (octal string) */
  1471.  
  1472.     *p++ = '0';
  1473.     *p++ = ' ';
  1474.  
  1475.     /* Number of files remaining (decimal number) */
  1476.  
  1477.     *p++ = '1';
  1478.     *p++ = ' ';
  1479.  
  1480.     /* Number of bytes remaining (decimal number) */
  1481.  
  1482.     NumToString(size, s);
  1483.     memcpy(p, s + 1, *s);
  1484.     p += *s;
  1485.     *p++ = 0;    /* Final NULL */
  1486.  
  1487.     /* Send ZFILE header with ZModem conversion, management and transport
  1488.     options followed by a ZCRCW data subpacket containing the file name,
  1489.     file length, modification date. */
  1490.  
  1491.     message = EmptyStr;
  1492.     for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1493.         hdr.position = 0;
  1494.         hdr.zfile.conv = text ? 0 : ZCBIN;
  1495.         hdr.zfile.manage = ZMCLOB;    /* Replace existing file */
  1496.         SendBinaryHeader(ZFILE, hdr);
  1497.         SendData(buffer, p - buffer, ZCRCW);
  1498. again:
  1499.         Update(message, retry);
  1500.         if (GetHeader(&type, &hdr)) {    /* Error */
  1501.             message = EmptyStr;
  1502.             continue;
  1503.         }
  1504.         switch (type) {
  1505.             case ZRINIT:
  1506.                 message = (Byte *)"\pZRINIT";
  1507.                 if (WaitZPAD(Settings.ZTimeout, 100) == FINE)
  1508.                     goto again;
  1509.                 break;
  1510.             case ZSKIP:
  1511.                 /* The receiver may respond with a ZSKIP header, which
  1512.                 makes the sender proceed to the next file (if any) in the
  1513.                 batch. */
  1514.                 *startpos = 0x7FFFFFFF;
  1515.                 err = FINE;
  1516.                 goto done;
  1517.             case ZRPOS:
  1518.                 *startpos = hdr.position;
  1519.                 err = FINE;
  1520.                 goto done;
  1521.         }
  1522.     }
  1523.     err = TIMEOUT;
  1524. done:
  1525.     Update(EmptyStr, 0);
  1526.     return err;
  1527. }
  1528.  
  1529. /* ----- Session cleanup ----------------------------------------------- */
  1530.  
  1531. static SessionCleanup (void)
  1532. {
  1533.     register short retry;
  1534.     HEADER hdr;
  1535.     Byte type;
  1536.     static Byte oo[] = "\pOO";    /* Over and out */
  1537.  
  1538.     for (retry = 0; retry < Settings.ZRetries; ++retry) {
  1539.         hdr.position = 0;
  1540.         SendHexHeader(ZFIN, hdr);
  1541.         if (GetHeader(&type, &hdr))
  1542.             continue;
  1543.         if (type == ZFIN) {
  1544.             SendString(oo + 1, oo[0]);
  1545. #ifdef MONITOR
  1546.             MonitorText(oo);
  1547. #endif
  1548.             return;
  1549.         }
  1550.     }
  1551. }
  1552.  
  1553. /* ----- Send a file --------------------------------------------------- */
  1554.  
  1555. short ZTransmit (Byte *name, short volume, long directory)
  1556. {
  1557.     short err;
  1558.     OSType creator, type;
  1559.     long create, modif;
  1560.     Byte tempname[20];
  1561.  
  1562.     StartTime = Time;
  1563.     Length = Mark = StartPos = 0;
  1564.     if (Sending || Transfer)
  1565.         return fBsyErr;
  1566.  
  1567.     /* Only send non-TEXT files as MacBinary if requested. TEXT files are
  1568.     never sent as MacBinary. For MacBinary we convert the file first,
  1569.     then use that temporay file to transmit. The temporay file will be
  1570.     deleted if we are finsihed. */
  1571.  
  1572.     if (err = InfoFile(volume, directory, name,
  1573.             &creator, &type, &create, &modif))
  1574.         return err;
  1575.     if (Vers = (Settings.Binary && type != TEXT) ? 2 : 0) {
  1576.         NumToString(Time, tempname);
  1577.         if ((err = Convert(volume, directory, name,
  1578.                 Settings.volume, Settings.directory, tempname)) ||
  1579.             (err = InfoFile(Settings.volume, Settings.directory, tempname,
  1580.                 &creator, &type, &create, &modif)) ||
  1581.             (err = OpenFile(Settings.volume, Settings.directory,
  1582.                 tempname, &RefNum))) {
  1583.             DeleteFile(Settings.volume, Settings.directory, tempname);
  1584.             return err;
  1585.         }
  1586.     } else {
  1587.         if (err = OpenFile(volume, directory, name, &RefNum))
  1588.             return err;
  1589.     }
  1590.  
  1591.     if (!(Buffer = (Byte *)NewPtr(ZMAXSPLEN))) {
  1592.         err = memFullErr;
  1593.         goto done1;
  1594.     }
  1595.     if (err = NewTxBuffer(TRUE))
  1596.         goto done1;
  1597.     Transfer = Transfer_Tx;
  1598.     SetItemStyle(GetMenu(FILE), TRANSMIT, ACTIVE);
  1599.     DrawProgressDialog(P_TFILE, name);
  1600.     GetEOF(RefNum, (long *)&Length);
  1601.     UpdateProgress(0, Length, 0, 0, 0, EmptyStr);
  1602.     MakeInfo();
  1603.  
  1604. #ifdef MONITOR
  1605.     MonitorOpen((Byte *)"\pTRANSMIT.DUMP", Settings.volume,
  1606.         Settings.directory);
  1607.     MonitorText((Byte *)"\pStart of Z-Modem transmit");
  1608. #endif
  1609.  
  1610.     Zctlesc = Escape();
  1611.     if (err = setjmp(CancelEnv)) {    /* Cancel or abort */
  1612.         SerialAbort();
  1613.         while (Busy)
  1614.             ;
  1615.         if (err == CANCEL)
  1616.             SendCancel();            /* Send cancel string */
  1617.         goto done;
  1618.     }
  1619.     if ((err = Invitation()) || (err = SessionStartup()) ||
  1620.         (err = SendFileInfo(name, Length, type == 'TEXT', modif, &Mark)))
  1621.         goto done;
  1622.     if (Mark != 0x7FFFFFFF) {    /* Not skip */
  1623.         if (Seek(Mark))
  1624.             goto done;
  1625.  
  1626.         /* Send file data */
  1627.  
  1628.         if (err = SendFileData())
  1629.             goto done;
  1630.     }
  1631.     SessionCleanup();
  1632.  
  1633. done:
  1634.  
  1635. #ifdef MONITOR
  1636.     MonitorText((Byte *)"\pEnd of Z-Modem transmit");
  1637.     MonitorClose();
  1638. #endif
  1639.  
  1640.     RemoveCancelDialog();
  1641.     Statistics(Mark - StartPos, Time - StartTime, err);
  1642.     SetItemStyle(GetMenu(FILE), TRANSMIT, 0);
  1643.     Transfer = 0;
  1644. done1:
  1645.     if (RefNum) {
  1646.         FSClose(RefNum);
  1647.         RefNum = 0;
  1648.     }
  1649.     DisposeTxBuffer();
  1650.     if (Buffer)
  1651.         DisposPtr((Ptr)Buffer);
  1652.     if (Vers)
  1653.             DeleteFile(Settings.volume, Settings.directory, tempname);
  1654.     return err;
  1655. }
  1656.  
  1657. /* ===== RECEIVE ======================================================= */
  1658.  
  1659. /* ----- Free bytes on the current file system ------------------------- */
  1660.  
  1661. static unsigned long GetFreeSpace (void)
  1662. {
  1663.     return 0xFFFFFFFF;    /* many free bytes ... */
  1664. }
  1665.  
  1666. /* ----- Ack a ZFIN packet, let byegones be byegones ------------------- */
  1667.  
  1668. static void AckOverAndOut (void)
  1669. {
  1670.     register short retry;
  1671.     register short err;
  1672.     HEADER hdr;
  1673.     Byte c;
  1674.  
  1675.     hdr.position = 0;
  1676.     for (retry = 0; retry < 3; ++retry) {
  1677.         SendHexHeader(ZFIN, hdr);
  1678.         err = ReadByte(&c, Settings.ZTimeout);
  1679. #ifdef MONITOR
  1680.         {
  1681.             Byte mon[256];
  1682.             FormatStr(mon, (Byte *)"\pOver c='%c' err=%i", c, err);
  1683.             MonitorText(mon);
  1684.         }
  1685. #endif
  1686.         if (err == FINE && c == 'O') {
  1687.             err = ReadByte(&c, 60);
  1688. #ifdef MONITOR
  1689.             {
  1690.                 Byte mon[256];
  1691.                 FormatStr(mon, (Byte *)"\pOut c='%c' err=%i", c, err);
  1692.                 MonitorText(mon);
  1693.             }
  1694. #endif
  1695.             return;    /* Over and Out */
  1696.         }
  1697.     }
  1698. }
  1699.  
  1700. /* ----- Initialize for Zmodem receive attempt ------------------------- */
  1701.  
  1702. static short TryZReceive (
  1703.     HEADER *filehdr)        /* Return sender's options */
  1704. {
  1705.     register Byte *message;    /* Message to display */
  1706.     HEADER hdr;                /* Header */
  1707.     Byte type;                /* Header type received */
  1708.     short retry;            /* Retry counter */
  1709.     short err;                /* Error code */
  1710.  
  1711.     for (retry = 0, message = EmptyStr; retry < Settings.ZRetries; ) {
  1712.         hdr.position = 0;
  1713.         if (TryZhdrType == ZRINIT) {    /* Capability flags */
  1714.             hdr.zrinit.bufsize = Settings.ZBuffer;
  1715.             hdr.zrinit.canfdx = 1;
  1716.             hdr.zrinit.canovio = 1;
  1717.             hdr.zrinit.escctl = Escape();
  1718.         }
  1719.         SendHexHeader(TryZhdrType, hdr);
  1720.         if (TryZhdrType == ZSKIP)        /* Don't skip too far */
  1721.             TryZhdrType = ZRINIT;
  1722. again:
  1723.         Update(message, retry);
  1724.         ++retry;
  1725.         if (GetHeader(&type, &hdr) == FINE) {
  1726.             switch (type) {
  1727.                 case ZFILE:
  1728.                     *filehdr = hdr;        /* Return file options */
  1729.                     TryZhdrType = ZRINIT;
  1730.                     if (!ReceiveData(Buffer, ZMAXSPLEN, &Count, &type) &&
  1731.                             type == ZCRCW) {
  1732.                         err = FINE;
  1733.                         goto done;        /* File name received */
  1734.                     }
  1735.                     SendHexHeader(ZNAK, hdr);
  1736.                     message = (Byte *)"\pZFILE error";
  1737.                     goto again;
  1738.                 case ZSINIT:
  1739.                     Zctlesc = hdr.zsinit.escctl;
  1740.                     if (!ReceiveData(Attn, ZATTNLEN, &AttnLen, &type) &&
  1741.                             type == ZCRCW) {
  1742.                         hdr.position = 1;
  1743.                         SendHexHeader(ZACK, hdr);
  1744.                         message = (Byte *)"\pZSINIT ok";
  1745.                         goto again;
  1746.                     }
  1747.                     SendHexHeader(ZNAK, hdr);
  1748.                     message = (Byte *)"\pZSINIT error";
  1749.                     goto again;
  1750.                 case ZFREECNT:
  1751.                     hdr.position = GetFreeSpace();
  1752.                     SendHexHeader(ZACK, hdr);
  1753.                     message = (Byte *)"\pZFREECNT";
  1754.                     goto again;
  1755.                 case ZCOMPL:
  1756.                     message = (Byte *)"\pZCOMPL";
  1757.                     goto again;
  1758.                 case ZFIN:
  1759.                     Update((Byte *)"\pZFIN", retry);
  1760.                     AckOverAndOut();
  1761.                     Count = 0;            /* Nothing in Buffer */
  1762.                     err = FINE;
  1763.                     goto done;
  1764.             }
  1765.         } else
  1766.             message = EmptyStr;
  1767.     }
  1768.     err = TIMEOUT;
  1769.     Count = 0;                            /* Nothing in Buffer */
  1770. done:
  1771.     Update(EmptyStr, 0);
  1772.     return err;
  1773. }
  1774.  
  1775. /* ----- Process incoming file information header ---------------------- */
  1776.  
  1777. static OSErr ProcedeHeader (
  1778.     HEADER filehdr,            /* Sender's options */
  1779.     Byte *name,                /* File name extracted (pascal string) */
  1780.     unsigned long *length,    /* File length extracted */
  1781.     unsigned long *modif)    /* Modification time extracted */
  1782. {
  1783.     register short err;
  1784.     register Byte *p, *max;
  1785.     register Byte c;
  1786.     Boolean exists;            /* File exists */
  1787.     Boolean append;            /* Append to existing file */
  1788.     OSType creator, type;
  1789.     long create, modif2;
  1790.  
  1791.     *name = 0;
  1792.     *length = 0;
  1793.     *modif = 0;
  1794.     RefNum = 0;
  1795.  
  1796.     /* Extract fields from file information header */
  1797.  
  1798.     max = (p = Buffer) + Count;
  1799.     err = 0;
  1800.     while (p < max) {
  1801.         c = *p++;
  1802.         switch (err) {
  1803.             case 0:    /* File name (C-string) */
  1804.                 if (c == '\0') {
  1805.                     memcpy(name + 1, Buffer, *name = p - 1 - Buffer);
  1806.                     ++err;    /* Goto next state */
  1807.                 }
  1808.                 break;
  1809.             case 1:    /* File length (decimal string, space) */
  1810.                 if (c == ' ' || c == '\0')
  1811.                     ++err;    /* Goto next state */
  1812.                 else
  1813.                     *length = *length * 10 + (c & 0x0F);
  1814.                 break;
  1815.             case 2:    /* File modification time (octal string, space) */
  1816.                 if (c == ' ' || c == '\0') {
  1817.                     ConvertTime(TRUE, modif);    /* -> Macintosh time */
  1818.                     ++err;    /* Goto next state */
  1819.                 } else
  1820.                     *modif = *modif * 8 + (c & 0x0F);
  1821.                 break;
  1822.             default:
  1823.                 break;
  1824.         }
  1825.     }
  1826.     if (err < 3)            /* Got no modification time...    */
  1827.         *modif = Time;        /* ...so use actual time        */
  1828.  
  1829.     /* See if file exists */
  1830.  
  1831.     exists = (InfoFile(Settings.volume, Settings.directory, name,
  1832.         &creator, &type, &create, &modif2) == noErr);
  1833.     append = exists &&
  1834.         creator == Application.signature &&
  1835.         type == Application.ztype;
  1836.  
  1837.     /* Skip file if not present at rx */
  1838.  
  1839.     if (filehdr.zfile.skip && !exists)
  1840.         return 100;
  1841.  
  1842.     /* Delete existing file */
  1843.  
  1844.     if (exists && filehdr.zfile.manage == ZMCLOB) {
  1845.         DeleteFile(Settings.volume, Settings.directory, name);
  1846.         exists = append = FALSE;
  1847.     }
  1848.  
  1849.     /* Create new file */
  1850.  
  1851.     if (!exists) {
  1852.         if (err = CreateFile(Settings.volume, Settings.directory,
  1853.                 name, Application.signature, Application.ztype))
  1854.             return err;
  1855.         exists = TRUE;
  1856.         append = FALSE;
  1857.     }
  1858.  
  1859.     /* Open file (append if necessary) */
  1860.  
  1861.     if (err = OpenFile(Settings.volume, Settings.directory, name, &RefNum))
  1862.         return err;
  1863.     if (append  && (err = SetFPos(RefNum, fsFromLEOF, 0))) {
  1864.         FSClose(RefNum);
  1865.         RefNum = 0;
  1866.         return err;
  1867.     }
  1868.  
  1869.     return FINE;
  1870. }
  1871.  
  1872. /* ----- Write buffer to file ------------------------------------------ */
  1873.  
  1874. static OSErr WriteFile (void)
  1875. {
  1876.     long count = Count;
  1877.     long df, rf;
  1878.     Byte name2[64];
  1879.  
  1880.     /* Check for MacBinary header. If valid MacBinary header is complete,
  1881.     use file name and file size from this header instead ZModem header. */
  1882.  
  1883.     if (Settings.Binary) {
  1884.         if (Mark < BinHeaderLength)
  1885.             memcpy(BinHdr, Buffer,
  1886.                 (Count < (BinHeaderLength - Mark)) ?
  1887.                 Count : BinHeaderLength - Mark);
  1888.         if (Mark >= BinHeaderLength && Vers < 0) {
  1889.             Vers = BinCheckHeader(BinHdr, name2, &df, &rf);
  1890.             MakeInfo();
  1891.             if (Vers > 0) {
  1892.                 NameProgress(name2);
  1893.                 Length = BinHeaderLength +
  1894.                     df + Filler(BinHeaderLength, df) +
  1895.                     rf + Filler(BinHeaderLength, rf);
  1896.             }
  1897.         }
  1898.     }
  1899.  
  1900.     /* Write buffer to file */
  1901.  
  1902.     return FSWrite(RefNum, &count, Buffer);
  1903. }
  1904.  
  1905. /* ----- File was completly received ----------------------------------- */
  1906.  
  1907. static void CleanupFile (
  1908.     Byte *name,                /* File name from ZModem header */
  1909.     unsigned long modif)    /* File modification time */
  1910. {
  1911.     short ref;
  1912.     Byte name2[64];            /* File name from MacBinary header */
  1913.     Byte name3[64];            /* Temporary file name */
  1914.     Byte header[BinHeaderLength];
  1915.     long count, data, resource;
  1916.     short err, err2;
  1917.  
  1918.     /* Set file creator/type and creation/modification time */
  1919.  
  1920.     if (SetInfoFile(Settings.volume, Settings.directory, name,
  1921.             Settings.binCreator, Settings.binType, modif, modif))
  1922.         return;
  1923.  
  1924.     /* Read file header to see if it is MacBinary */
  1925.  
  1926.     if (!Settings.Binary ||
  1927.             OpenFile(Settings.volume, Settings.directory, name, &ref))
  1928.         return;
  1929.     count = sizeof(header);
  1930.     if (FSRead(ref, &count, header) ||
  1931.             count != sizeof(header) ||
  1932.             !BinCheckHeader(header, name2, &data, &resource)) {
  1933.         FSClose(ref);
  1934.         return;
  1935.     }
  1936.  
  1937.     /* Create a new file with an unique name to become the final file */
  1938.  
  1939.     NumToString(Time, name3);
  1940.     if (CreateFile(Settings.volume, Settings.directory, name3,
  1941.             '????', '????')) {
  1942.         FSClose(ref);
  1943.         return;
  1944.     }
  1945.     if (BinOpenWrite(Settings.volume, Settings.directory, name3, header)) {
  1946.         DeleteFile(Settings.volume, Settings.directory, name3);
  1947.         FSClose(ref);
  1948.         return;
  1949.     }
  1950.  
  1951.     /* Extract from MacBinary file to new file */
  1952.  
  1953.     err = CopyFile(ref);
  1954.     FSClose(ref);
  1955.     err2 = BinCloseWrite();
  1956.     if (err || err2) {
  1957.         DeleteFile(Settings.volume, Settings.directory, name3);
  1958.         return;
  1959.     }
  1960.  
  1961.     /* Delete original file, rename extracted file to name from MacBinary
  1962.     header (if this does not work use name from ZModem header). */
  1963.  
  1964.     DeleteFile(Settings.volume, Settings.directory, name);
  1965.     if (FileRename(Settings.volume, Settings.directory, name3, name2))
  1966.         FileRename(Settings.volume, Settings.directory, name3, name);
  1967. }
  1968.  
  1969. /* ----- Receive a file ------------------------------------------------ */
  1970.  
  1971. static short ReceiveFile (
  1972.     HEADER filehdr)            /* Sender's options */
  1973. {
  1974.     register short err;        /* Error code */
  1975.     register short retry;    /* Retry counter */
  1976.     register Byte *message;    /* Message to display */
  1977.     Byte name[256];            /* File name from Z header (Pascal string) */
  1978.     Byte name2[64];            /* File name from MacBin hdr (Pascal string) */
  1979.     unsigned long modif;    /* File modification date (Mac time) */
  1980.     HEADER hdr;                /* Header */
  1981.     Byte type;                /* Header type received */
  1982.     Byte end;                /* Data frame type */
  1983.  
  1984.     /* Get ready to receive new file */
  1985.  
  1986.     Vers = -1;
  1987.     StartPos = Mark = Length = 0;
  1988.     if (ProcedeHeader(filehdr, name, &Length, &modif)) {
  1989.         /* Error or skip, but that's fine! */
  1990.         TryZhdrType = ZSKIP;
  1991.         return FINE;
  1992.     }
  1993.     GetFPos(RefNum, (long *)&StartPos);
  1994.     Mark = StartPos;
  1995.  
  1996.     /* If resuming previous receive fill MacBinary header. If we already
  1997.     have a valid MacBinary header use the name and the file size from this
  1998.     header instead of from the ZModem header. */
  1999.  
  2000.     if (Settings.Binary && Mark > 0) {
  2001.         long count = (Mark > BinHeaderLength) ? BinHeaderLength : Mark;
  2002.         long df, rf;
  2003.  
  2004.         SetFPos(RefNum, fsFromStart, 0);
  2005.         FSRead(RefNum, &count, BinHdr);
  2006.         SetFPos(RefNum, fsFromStart, Mark);
  2007.         if (count >= BinHeaderLength)
  2008.             if (Vers = BinCheckHeader(BinHdr, name2, &df, &rf))
  2009.                 Length = BinHeaderLength +
  2010.                     df + Filler(BinHeaderLength, df) +
  2011.                     rf + Filler(BinHeaderLength, rf);
  2012.     }
  2013.     NameProgress(Vers > 0 ? name2 : name);
  2014.     Rxbuflen = Settings.ZBuffer;
  2015.     MakeInfo();
  2016.  
  2017.     /* Receiving loop */
  2018.  
  2019.     for (retry = 0, message = EmptyStr; ; ) {
  2020.         hdr.position = Mark;
  2021.         SendHexHeader(ZRPOS, hdr);
  2022. nxthdr:
  2023.         Update(message, retry);
  2024.         switch (GetHeader(&type, &hdr)) {
  2025.             case FINE:
  2026.                 switch (type) {
  2027.                     case ZNAK:
  2028.                         ++retry;
  2029.                         if (retry > Settings.ZRetries) {
  2030.                             err = ERROR;
  2031.                             goto done;
  2032.                         }
  2033.                         message = (Byte *)"\phdr-ZNAK";
  2034.                         break;
  2035.                     case ZFILE:
  2036.                         err = ReceiveData(Buffer, ZMAXSPLEN, &Count, &end);
  2037.                         message = (Byte *)"\phdr-ZFILE";
  2038.                         break;
  2039.                     case ZEOF:
  2040.                         /* Ignore eof if it's at wrong place - force a
  2041.                         timeout because the eof might have gone out before
  2042.                         we sent our zrpos. */
  2043.                         message = (Byte *)"\phdr-ZEOF";
  2044.                         if (hdr.position != Mark)
  2045.                             goto nxthdr;            /* Ignore this eof */
  2046.                         FSClose(RefNum);
  2047.                         RefNum = 0;
  2048.                         Update(message, retry);
  2049.                         CleanupFile(name, modif);
  2050.                         err = FINE;                    /* Normal eof */
  2051.                         goto done;
  2052.                     case ZSKIP:
  2053.                         message = (Byte *)"\phdr-ZSKIP";
  2054.                         FSClose(RefNum);
  2055.                         RefNum = 0;
  2056.                         err = FINE;                    /* Sender skipped it */
  2057.                         goto done;
  2058.                     case ZDATA:
  2059.                         message = (Byte *)"\phdr-ZDATA";
  2060.                         if (hdr.position != Mark) {
  2061.                             ++retry;
  2062.                             if (retry > Settings.ZRetries) {
  2063.                                 err = ERROR;
  2064.                                 goto done;
  2065.                             }
  2066.                             SendAttn(Attn);
  2067.                             break;
  2068.                         }
  2069. moredata:
  2070.                         Update(message, retry);
  2071.                         switch (ReceiveData(Buffer, ZMAXSPLEN, &Count, &end)) {
  2072.                             case TIMEOUT:
  2073.                                 ++retry;
  2074.                                 if (retry > Settings.ZRetries) {
  2075.                                     err = ERROR;
  2076.                                     goto done;
  2077.                                 }
  2078.                                 message = (Byte *)"\pdata-TIMEOUT";
  2079.                                 break;
  2080.                             case ERROR:
  2081.                                 ++retry;
  2082.                                 if (retry > Settings.ZRetries) {
  2083.                                     err = ERROR;
  2084.                                     goto done;
  2085.                                 }
  2086.                                 SendAttn(Attn);
  2087.                                 message = (Byte *)"\pdata-ERROR";
  2088.                                 break;
  2089.                             case FINE:
  2090.                                 retry = 0;
  2091.                                 WriteFile();
  2092.                                 Mark += Count;
  2093.                                 switch (end) {
  2094.                                     case ZCRCW:
  2095.                                         message = (Byte *)"\pdata-ZCRCW";
  2096.                                         hdr.position = Mark;
  2097.                                         SendHexHeader(ZACK, hdr);
  2098.                                         goto nxthdr;
  2099.                                     case ZCRCQ:
  2100.                                         message = (Byte *)"\pdata-ZCRCQ";
  2101.                                         hdr.position = Mark;
  2102.                                         SendHexHeader(ZACK, hdr);
  2103.                                         goto moredata;
  2104.                                     case ZCRCG:
  2105.                                         message = (Byte *)"\pdata-ZCRCG";
  2106.                                         goto moredata;
  2107.                                     case ZCRCE:
  2108.                                         message = (Byte *)"\pdata-ZCRCE";
  2109.                                         goto nxthdr;
  2110.                                 }
  2111.                                 break;
  2112.                         }
  2113.                         break;
  2114.                     default:
  2115.                         err = ERROR;
  2116.                         goto done;
  2117.                 }
  2118.                 break;
  2119.             case TIMEOUT:
  2120.                 ++retry;
  2121.                 if (retry > Settings.ZRetries) {
  2122.                     err = ERROR;
  2123.                     goto done;
  2124.                 }
  2125.                 message = (Byte *)"\phdr-TIMEOUT";
  2126.                 break;
  2127.             case ERROR:
  2128.                 ++retry;
  2129.                 if (retry > Settings.ZRetries) {
  2130.                     err = ERROR;
  2131.                     goto done;
  2132.                 }
  2133.                 SendAttn(Attn);
  2134.                 message = (Byte *)"\phdr-ERROR";
  2135.                 break;
  2136.         }
  2137.     }
  2138.  
  2139. done:
  2140.     Update(EmptyStr, retry);
  2141.     return err;
  2142. }
  2143.  
  2144. /* ----- Receive one or more files ------------------------------------- */
  2145.  
  2146. static short ReceiveFiles (void)
  2147. {
  2148.     register short err;
  2149.     HEADER filehdr;            /* Sender's options */
  2150.  
  2151.     Mark = StartPos = 0;
  2152.     StartTime = Time;
  2153.     Zctlesc = Escape();
  2154.     TryZhdrType = ZRINIT;
  2155.     Attn[0] = 0;            /* Clear sender's attention string */
  2156.     AttnLen = 0;
  2157.  
  2158.     for (;;) {
  2159.         NameProgress(EmptyStr);
  2160.         InfoProgress(EmptyStr);
  2161.         UpdateProgress(0, 0, 0, 0, 0, EmptyStr);
  2162.         StartTime = Time;
  2163.         err = TryZReceive(&filehdr);
  2164.         if (!Count) {
  2165.             if (err)
  2166.                 Statistics(0, Time - StartTime, err);
  2167.             return err;
  2168.         }
  2169.         ConvertNL = filehdr.zfile.conv == ZCNL;
  2170.         err = ReceiveFile(filehdr);
  2171.         Statistics(Mark - StartPos, Time - StartTime, err);
  2172.         if (err)
  2173.             return err;
  2174.     }
  2175. }
  2176.  
  2177. /* ----- ZModem receive ------------------------------------------------ */
  2178.  
  2179. short ZReceive (void)
  2180. {
  2181.     register short err = 0;
  2182.  
  2183.     if (Sending || Transfer)
  2184.         return fBsyErr;
  2185.     StartTime = Time;
  2186.     RefNum = 0;                        /* No file open yet */
  2187.     Mark = Length = StartPos = 0;
  2188.     if (!(Buffer = (Byte *)NewPtr(BUFFERSIZE))) {
  2189.         err = memFullErr;
  2190.         goto done;                    /* Not enough memory */
  2191.     }
  2192.     if (err = NewTxBuffer(FALSE))    /* We only will send headers */
  2193.         goto done;                    /* Not enough memory */
  2194.     Transfer = Transfer_Rx;
  2195.     SetItemStyle(GetMenu(FILE), RECEIVE, ACTIVE);
  2196.     if (Settings.handshake == 1)    /* XON/OFF must be off */
  2197.         SerialHandshake(0);
  2198.     DrawProgressDialog(P_RFILE, EmptyStr);
  2199.     UpdateProgress(0, 0, 0, 0, 0, EmptyStr);
  2200.  
  2201. #ifdef MONITOR
  2202.     MonitorOpen((Byte *)"\pRECEIVE.DUMP", Settings.volume,
  2203.         Settings.directory);
  2204.     MonitorText((Byte *)"\pStart of Z-Modem receive");
  2205. #endif
  2206.  
  2207.     if (err = setjmp(CancelEnv)) {    /* Prepare cancel or abort */
  2208.         Statistics(Mark - StartPos, Time - StartTime, err);
  2209.         SerialAbort();
  2210.         while (Busy)
  2211.             ;
  2212.         if (err == CANCEL)
  2213.             SendCancel();            /* Send cancel string */
  2214.     } else
  2215.         err = ReceiveFiles();        /* Receive file(s) */
  2216.  
  2217. #ifdef MONITOR
  2218.     MonitorText((Byte *)"\pEnd of Z-Modem receive");
  2219.     MonitorClose();
  2220. #endif
  2221.  
  2222.     RemoveCancelDialog();
  2223.     SerialHandshake(Settings.handshake);
  2224.     SetItemStyle(GetMenu(FILE), RECEIVE, 0);
  2225.     Transfer = 0;
  2226.  
  2227. done:
  2228.     if (RefNum) {                    /* Close any open file */
  2229.         FSClose(RefNum);
  2230.         RefNum = 0;
  2231.     }
  2232.     DisposeTxBuffer();                /* Get rid of transmit buffer */
  2233.     if (Buffer)                        /* Get rid of receive buffer */
  2234.         DisposPtr((Ptr)Buffer);
  2235.     return err;
  2236. }
  2237.